from flask import Flask, render_template, Response, request, jsonify, stream_with_context
import RPi.GPIO as GPIO
import cv2
from components.motor_driver import Motor
from components.servo_vertical_axis import Vertical_Axis

# picamera andopencv
from components.cv_picamera import CameraStream
from components.cv_image import add_ultrasonic_servo_angle_to_image

# the extended componets
from components.display_tm1637 import Display_4
from components.sonar import Ultrasonic
from components.display_tm1637 import Display_4
from components.ir_avoidance import Infrared_Avoidance
from components.laser_shot import Laser

import json
import time
# the extended componets
import threading

GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)
GPIO.cleanup()

motor = Motor(5,6,27,17)
ultrasonic_servo=Vertical_Axis(18,90)
camera_cap = CameraStream().start()

# the extended componets
# ultrasonic
ultrasonic=Ultrasonic(24,23)
ul_thread=threading.Thread(target=ultrasonic.worker,args=(motor,),daemon=True)
ul_thread.start()

# display 4
display4 =  Display_4(1,0) # CLK,DIO
d4_thread = threading.Thread(target=display4.worker,args=(ultrasonic,),daemon=True)
d4_thread.start()

# ir_avoidance
ir_avoidance=Infrared_Avoidance(22,16) # left,right
ir_avoidance_thread = threading.Thread(target=ir_avoidance.worker,args=(motor,),daemon=True)
ir_avoidance_thread.start()

# laser
laser=Laser(26) # singal


def gen_frame():
    """Video streaming generator function"""
    while camera_cap:
        frame = camera_cap.read()
        # modified the frame
        frame=add_ultrasonic_servo_angle_to_image(frame,ultrasonic_servo)
        convert = cv2.imencode('.jpg', frame)[1].tobytes()
        yield (b'--frame\r\n'
               b'Content-Type: image/jpeg\r\n\r\n' + convert + b'\r\n')  # concate frame one by one and show result

app = Flask(__name__)


@app.route('/video_feed')
def video_feed():
    """Video streaming route. Put this in the src attribute of an img tag."""
    return Response(gen_frame(),
                    mimetype='multipart/x-mixed-replace; boundary=frame')


@app.route('/data')
def data():
    def generate_data():
        while True:
            json_data = json.dumps({'distance': ultrasonic.distance,'speed': motor.speed})
            yield f"data:{json_data}\n\n"
            time.sleep(0.3)

    response = Response(stream_with_context(
        generate_data()), mimetype="text/event-stream")
    response.headers["Cache-Control"] = "no-cache"
    response.headers["X-Accel-Buffering"] = "no"
    return response

@app.route('/', methods=['GET', 'POST'])
def main():
    return render_template("index.html")


@app.route('/car_action', methods=['GET'])
def car_action():
    m_action = int(request.args.get('action'))
    motor.action(m_action)
    return jsonify({'motor status':m_action})

@app.route('/ultrasonic_servo_action', methods=['GET'])
def ultrasonic_servo_action():
    ultrasonic_servo_action = int(request.args.get('action'))
    ultrasonic_servo.action(ultrasonic_servo_action)
    return jsonify({'ultrasonic_servo_action status':ultrasonic_servo_action})

@app.route('/opencv_action', methods=['GET'])
def opencv_action():
    opencv_action = int(request.args.get('action'))
    camera_cap.cur_opencv_action=opencv_action
    return jsonify({'opencv status':opencv_action})

@app.route('/laser_action', methods=['GET'])
def laser_action():
    laser_action = int(request.args.get('action'))
    laser.action(laser_action)
    return jsonify({'laser status':laser_action})

if __name__ == "__main__":
    app.run(host='0.0.0.0', port=5000, debug=False)
    cv2.destroyAllWindows()
    GPIO.cleanup()
